Processing ECG signal
Copyright (C) 2022 Miodrag Bolic
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details <https://www.gnu.org/licenses/>.
Acknowledgements
This notebook uses modified code written by Hooman Sedghamiz to compute fiducial points of the ECG signal: MTEO_qrst.m . It also uses the function moving.m developed by Aslak Grinsted for computing the moving average.
Dependencies: ecg.mat, MTEO_qrst.m, adaptive_noise_model.m, moving.m
% Changing the path from main_folder to a particular chapter
main_path=fileparts(which('Main_Content.mlx'));
%addpath(append(main_path,'/Chapter2'))
cd (append(main_path,'/Chapter7/ECG Processing'))
addpath(append(main_path,'/Service'))
SAVE_FLAG=0; % saving the figures in a file
Introduction
In this notebook, we are going to load ECG signal and consider 3 cases:
Case 1: High quality ECG signal
Case 2: ECG signal with Gaussian noise and 60 Hz noise
Case 3: Impulse noise and high SNR
Then, we are going to estimate the heart rate and to detect all the important waves on the ECG signal.
case123=2; % modify this number and run simulation for cases 1, 2 and 3
% ecg = decimate(ecg,ratio);
noise=additive_noise_model(N, fs, 'Gaussian', [0, 0.1], '60 Hz', [0.1], 'Plotting');
noise=additive_noise_model(N, fs, 'BandLimited Impulse', [2, 1, 10], 'Gaussian', [0, 0.01],'Plotting');
annonation_save('a)',"Fig7.7a.jpg", SAVE_FLAG);
Offline algorithm for estimating heart rate
t=1/fs:1/fs:length(ecg)/fs;
Filtering
ecg_BP = bandpass(ecg,[1,20],fs);
ylabel('Amplitude (mV)');
title('Signal after band-pass filter');
annonation_save('b)',"Fig7.7b.jpg", SAVE_FLAG);
Differentiator
b = firls(30,[0 0.9],[0 0.9*pi],'differentiator');
%fvtool(b,1,'MagnitudeDisplay','zero-phase')
ecg_diff = filter(b,1,ecg_BP);
ylabel('Amplitude (mV)');
title('Signal after differentiation');
annonation_save('c)',"Fig7.7c.jpg", SAVE_FLAG);
Absolute vaue or squaring
plot(t,ecg_sq/max(ecg_sq))
ylabel('Normalized amplitude');
title('Signal after squaring');
annonation_save('d)',"Fig7.7d.jpg", SAVE_FLAG);
Time averaging
ecg_av=moving(ecg_sq,31);
plot(t,ecg_av/max(ecg_av))
ylabel('Normalized amplitude');
title('Signal after sliding window averaging');
annonation_save('e)',"Fig7.7e.jpg", SAVE_FLAG);
Presenting the digital pulses
thresh = max_h/2; %mean(ecg_av);
r_wave_instances =(ecg_av > thresh)';
ylabel('Pulse amplitude');
title('R wave instances');
annonation_save('f)',"Fig7.7f.jpg", SAVE_FLAG);
Heart rate based on the number of pulses in the specific time interval
[dypks,ix] = findpeaks(double(r_wave_instances), 'MinPeakDistance',fs/2, 'MinPeakProminence',0.5); % Zero-Crossings & Indices
heart_rate1=round(60*length(ix)/t(end));
X=['Heart rate based on the number of pulses in the specific time interval: ', num2str(heart_rate1), ' beats per min'];
disp(X)
Heart rate based on the number of pulses in the specific time interval: 46 beats per min
Heart rate based on the average RR interval
heart_rate2=round(60*fs/mean_RR);
X=['Heart rate based on the average RR interval: ', num2str(heart_rate2), ' beats per min'];
disp(X)
Heart rate based on the average RR interval: 46 beats per min
Exersizes
Excersize 1: Estimate heart rate for the cases when ECG pulses are corrupted by noise. Comment on when the algorithm start failing
Delineating the ECG signal
[R1,Q,S,T,P_w, Te, ecg1] = MTEO_qrst(ecg,fs,0);
hold on,scatter(R1(:,1)/fs,R1(:,2),'r');
hold on,scatter(Q(:,1)/fs,Q(:,2),'g');
hold on,scatter(S(:,1)/fs,S(:,2),'k');
hold on,scatter(T(:,1)/fs,T(:,2),'m');
hold on,scatter(P_w(:,1)/fs,P_w(:,2),'MarkerEdgeColor',[.7 .5 0]);
legend({'ECG signal','R wave','Q wave','S wave','T wave', 'P wave'},'NumColumns',2)
title('Delineated ECG signal')
exportgraphics(gcf,"Fig7.19.jpg", 'Resolution',600)